package netnotifier.builder;

import java.util.Arrays;
import java.util.HashMap;

import netnotifier.NetNotifier;
import netnotifier.notification.HTTPGet;
import netnotifier.notification.HTTPPost;
import netnotifier.notification.HTTPResponse;
import netnotifier.notification.TCPRead;
import netnotifier.notification.TCPWrite;

public class HTTPBuilder
{
	private NetNotifier notifier=NetNotifier.instance;
	
	public HTTPBuilder()
	{
		try
		{
			notifier.subscribe(TCPWrite.class, this, "gotTCPWrite");
			notifier.subscribe(TCPRead.class, this, "gotTCPRead");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	public void gotTCPWrite(Object o)
	{
		//System.out.println("got a TCP write");
		
		if(!(o instanceof TCPWrite))return;
		TCPWrite tcpWrite=(TCPWrite)o;
		
		if(tcpWrite.length<10)return;
		// pull in first 10 bytes of data
		String request=new String(tcpWrite.data,0,10);
		
		// if request does not contain a space, return
		int index=request.indexOf(' ');
		if(index==-1)
		{
			System.out.println("threw away "+tcpWrite.clientIP+" -> "+tcpWrite.serverIP);
			return;
		}
		
		// strip request string down to the request verb
		request=request.substring(0,index);
		
		if(request.equals("GET"))parseGet(tcpWrite);
		else if(request.equals("POST"))parsePost(tcpWrite);
	}
	
	private void parseGet(TCPWrite tcpWrite)
	{
		String[] request=new String(tcpWrite.data).split("\r\n");
		
		// make sure the request has at least 2 parts
		if(request.length<2)return;
		
		HTTPGet get=new HTTPGet();
		
		String[] requestHeader=request[0].split(" ");
		get.path=requestHeader[1];
		get.version=requestHeader[2];
		get.clientIP=tcpWrite.clientIP;
		get.serverIP=tcpWrite.serverIP;
		
		// parse out the get options
		get.options=new HashMap<String,String>();
		for(int x=1;x<request.length;++x)
		{
			// parse the data portion if it exists
			if(request[x]=="")
			{
				if(request.length>x)get.data=request[x+1];
				continue;
			}
			
			// parse out this option
			String[] option=request[x].split(": ");
			if(option.length!=2)
			{
				System.out.println("malformed option: "+request[x]);
				continue;
			}
			
			// add this option to the hashmap of options
			if(option[0].equals("Host"))get.host=option[1];
			else
			{
				get.options.put(option[0],option[1]);
			}		
		}
		
		notifier.contribute(get);
	}

	private void parsePost(TCPWrite tcpWrite)
	{
		String[] request=new String(tcpWrite.data).split("\r\n");
		
		// make sure the request has at least 2 parts
		if(request.length<2)return;
		
		HTTPPost post=new HTTPPost();
		
		String[] requestHeader=request[0].split(" ");
		post.path=requestHeader[1];
		post.version=requestHeader[2];
		post.clientIP=tcpWrite.clientIP;
		post.serverIP=tcpWrite.serverIP;
		
		// parse out the post options
		post.options=new HashMap<String,String>();
		for(int x=1;x<request.length;++x)
		{
			// parse the data portion
			if(request[x].equals(""))
			{
				if(request.length>x)
				{
					String[] postValues=request[x+1].split("&");
					HashMap<String,String> postData=new HashMap<String,String>();
					for(String postValue:postValues)
					{
						//System.out.println("postvalue: "+postValue);
						String[] values=postValue.split("=");
						if(values.length==1)postData.put(values[0],"");
						else if(values.length==2)postData.put(values[0],values[1]);
					}
					post.postData=postData;
				}
				continue;
			}
			
			// parse out this option
			String[] option=request[x].split(": ");
			if(option.length!=2)
			{
				//System.out.println("malformed option: "+request[x]);
				continue;
			}
			
			// add this option to the hashmap of options
			if(option[0].equals("Host"))post.host=option[1];
			else
			{
				post.options.put(option[0],option[1]);
			}		
		}
		
		notifier.contribute(post);
	}

	public void gotTCPRead(Object o)
	{
		if(!(o instanceof TCPRead))return;
		TCPRead tcpRead=(TCPRead)o;
		
		if(tcpRead.length<10)return;
		if(!(new String(Arrays.copyOfRange(tcpRead.data,0,4)).equals("HTTP")))
		{
			//System.out.println("This is not an HTTP response");
			return;
		}
		
		// create the HTTPResponse
		HTTPResponse httpResponse=new HTTPResponse();
		httpResponse.clientIP=tcpRead.clientIP;
		httpResponse.serverIP=tcpRead.serverIP;
		
		// find where the options end and the file begins
		int fileOffset=new String(tcpRead.data).indexOf("\r\n\r\n");
		fileOffset+=4;
		
		// make sure the data is the right size before copying over options
		if(tcpRead.data.length<fileOffset)return;
		String optionString=new String(Arrays.copyOfRange(tcpRead.data,0,fileOffset));
		
		// set the HTTPResponse data
		httpResponse.data=Arrays.copyOfRange(tcpRead.data,fileOffset,tcpRead.data.length);
		
		String[] optionArray=optionString.split("\r\n");
		
		// the first element in the array should be the HTTP header
		String[] responseHeader=optionArray[0].split(" ",2); // split the string on the first space
		if(responseHeader.length!=2)return; // should always be 2
		httpResponse.version=responseHeader[0];
		httpResponse.status=responseHeader[1];
		
		httpResponse.options=new HashMap<String,String>();
		for(int x=1;x<optionArray.length;++x)
		{
			// parse out this option
			String[] option=optionArray[x].split(": ");
			if(option.length!=2)
			{
				System.out.println("malformed option: "+optionArray[x]);
				continue;
			}
			
			// add this option to the hashmap of options
			if(option[0].equals("Content-Type"))httpResponse.contentType=option[1];
			httpResponse.options.put(option[0],option[1]);
		}
		
		// the response looks good
		notifier.contribute(httpResponse);
	}
}
